const jwt = require('jsonwebtoken');
const { db } = require('../config/database');
const DiceParser = require('../utils/diceParser');

class WebSocketService {
  constructor(io) {
    this.io = io;
    this.diceParser = new DiceParser();
    this.setupEventHandlers();
  }

  setupEventHandlers() {
    this.io.on('connection', (socket) => {
      console.log('用户连接:', socket.id);

      // 用户认证
      socket.on('authenticate', async (data) => {
        try {
          const decoded = jwt.verify(data.token, process.env.JWT_SECRET);
          const user = await db.oneOrNone(
            'SELECT id, username, avatar FROM users WHERE id = $1',
            [decoded.userId]
          );

          if (user) {
            socket.userId = user.id;
            socket.username = user.username;
            socket.avatar = user.avatar;
            socket.emit('authenticated', { user });
            console.log(`用户 ${user.username} 认证成功`);
          } else {
            socket.emit('auth_error', { message: '用户不存在' });
          }
        } catch (error) {
          socket.emit('auth_error', { message: '认证失败' });
        }
      });

      // 加入房间
      socket.on('join-room', async (data) => {
        try {
          const { roomId } = data;
          
          if (!socket.userId) {
            socket.emit('error', { message: '请先认证' });
            return;
          }

          // 检查用户是否在房间中
          const room = await db.oneOrNone(
            'SELECT id, players, kp_id FROM rooms WHERE id = $1',
            [roomId]
          );

          if (!room) {
            socket.emit('error', { message: '房间不存在' });
            return;
          }

          const players = JSON.parse(room.players);
          if (!players.includes(socket.userId) && room.kp_id !== socket.userId) {
            socket.emit('error', { message: '您不在此房间中' });
            return;
          }

          socket.join(`room-${roomId}`);
          socket.currentRoomId = roomId;

          // 通知房间内其他用户
          socket.to(`room-${roomId}`).emit('user-joined', {
            userId: socket.userId,
            username: socket.username,
            avatar: socket.avatar
          });

          console.log(`用户 ${socket.username} 加入房间 ${roomId}`);
        } catch (error) {
          console.error('加入房间错误:', error);
          socket.emit('error', { message: '加入房间失败' });
        }
      });

      // 离开房间
      socket.on('leave-room', (data) => {
        const { roomId } = data;
        socket.leave(`room-${roomId}`);
        socket.currentRoomId = null;

        // 通知房间内其他用户
        socket.to(`room-${roomId}`).emit('user-left', {
          userId: socket.userId,
          username: socket.username
        });

        console.log(`用户 ${socket.username} 离开房间 ${roomId}`);
      });

      // 游戏状态更新
      socket.on('game-state-update', async (data) => {
        try {
          const { roomId, gameState } = data;

          if (!socket.currentRoomId || socket.currentRoomId !== roomId) {
            socket.emit('error', { message: '您不在此房间中' });
            return;
          }

          // 检查用户是否是KP
          const room = await db.oneOrNone(
            'SELECT kp_id FROM rooms WHERE id = $1',
            [roomId]
          );

          if (!room || room.kp_id !== socket.userId) {
            socket.emit('error', { message: '只有KP可以更新游戏状态' });
            return;
          }

          // 更新数据库
          await db.none(
            'UPDATE rooms SET game_state = $1, updated_at = CURRENT_TIMESTAMP WHERE id = $2',
            [JSON.stringify(gameState), roomId]
          );

          // 广播给房间内所有用户
          this.io.to(`room-${roomId}`).emit('game-state-updated', {
            gameState,
            updatedBy: socket.username,
            timestamp: new Date().toISOString()
          });

        } catch (error) {
          console.error('游戏状态更新错误:', error);
          socket.emit('error', { message: '更新游戏状态失败' });
        }
      });

      // 地图数据更新
      socket.on('map-data-update', async (data) => {
        try {
          const { roomId, mapData } = data;

          if (!socket.currentRoomId || socket.currentRoomId !== roomId) {
            socket.emit('error', { message: '您不在此房间中' });
            return;
          }

          // 检查用户是否是KP
          const room = await db.oneOrNone(
            'SELECT kp_id FROM rooms WHERE id = $1',
            [roomId]
          );

          if (!room || room.kp_id !== socket.userId) {
            socket.emit('error', { message: '只有KP可以更新地图数据' });
            return;
          }

          // 更新数据库
          await db.none(
            'UPDATE rooms SET map_data = $1, updated_at = CURRENT_TIMESTAMP WHERE id = $2',
            [JSON.stringify(mapData), roomId]
          );

          // 广播给房间内所有用户
          this.io.to(`room-${roomId}`).emit('map-data-updated', {
            mapData,
            updatedBy: socket.username,
            timestamp: new Date().toISOString()
          });

        } catch (error) {
          console.error('地图数据更新错误:', error);
          socket.emit('error', { message: '更新地图数据失败' });
        }
      });

      // 骰子掷骰
      socket.on('dice-roll', async (data) => {
        try {
          const { roomId, command } = data;

          if (!socket.currentRoomId || socket.currentRoomId !== roomId) {
            socket.emit('error', { message: '您不在此房间中' });
            return;
          }

          // 解析骰子指令
          const result = this.diceParser.parseCommand(command);

          // 记录骰子结果到数据库
          await db.none(
            'INSERT INTO dice_records (room_id, user_id, command, result) VALUES ($1, $2, $3, $4)',
            [roomId, socket.userId, command, JSON.stringify(result)]
          );

          // 广播骰子结果给房间内所有用户
          this.io.to(`room-${roomId}`).emit('dice-result', {
            result,
            user: {
              id: socket.userId,
              username: socket.username,
              avatar: socket.avatar
            },
            timestamp: new Date().toISOString()
          });

        } catch (error) {
          console.error('骰子掷骰错误:', error);
          socket.emit('error', { message: error.message || '掷骰失败' });
        }
      });

      // 聊天消息
      socket.on('chat-message', async (data) => {
        try {
          const { roomId, message, messageType = 'text' } = data;

          if (!socket.currentRoomId || socket.currentRoomId !== roomId) {
            socket.emit('error', { message: '您不在此房间中' });
            return;
          }

          // 保存聊天记录到数据库
          await db.none(
            'INSERT INTO chat_messages (room_id, user_id, message, message_type) VALUES ($1, $2, $3, $4)',
            [roomId, socket.userId, message, messageType]
          );

          // 广播聊天消息给房间内所有用户
          this.io.to(`room-${roomId}`).emit('chat-message', {
            message,
            messageType,
            user: {
              id: socket.userId,
              username: socket.username,
              avatar: socket.avatar
            },
            timestamp: new Date().toISOString()
          });

        } catch (error) {
          console.error('聊天消息错误:', error);
          socket.emit('error', { message: '发送消息失败' });
        }
      });

      // 角色属性更新
      socket.on('character-update', async (data) => {
        try {
          const { roomId, characterData } = data;

          if (!socket.currentRoomId || socket.currentRoomId !== roomId) {
            socket.emit('error', { message: '您不在此房间中' });
            return;
          }

          // 更新角色数据
          await db.none(
            'UPDATE characters SET stats = $1, skills = $2, inventory = $3, updated_at = CURRENT_TIMESTAMP WHERE user_id = $4',
            [
              JSON.stringify(characterData.stats || {}),
              JSON.stringify(characterData.skills || {}),
              JSON.stringify(characterData.inventory || []),
              socket.userId
            ]
          );

          // 广播角色更新给房间内所有用户
          this.io.to(`room-${roomId}`).emit('character-updated', {
            userId: socket.userId,
            characterData,
            updatedBy: socket.username,
            timestamp: new Date().toISOString()
          });

        } catch (error) {
          console.error('角色属性更新错误:', error);
          socket.emit('error', { message: '更新角色属性失败' });
        }
      });

      // 断开连接
      socket.on('disconnect', () => {
        console.log('用户断开连接:', socket.id);
        
        if (socket.currentRoomId) {
          // 通知房间内其他用户
          socket.to(`room-${socket.currentRoomId}`).emit('user-left', {
            userId: socket.userId,
            username: socket.username
          });
        }
      });
    });
  }

  // 发送系统消息
  sendSystemMessage(roomId, message) {
    this.io.to(`room-${roomId}`).emit('system-message', {
      message,
      timestamp: new Date().toISOString()
    });
  }

  // 强制断开用户连接
  disconnectUser(userId) {
    this.io.sockets.sockets.forEach(socket => {
      if (socket.userId === userId) {
        socket.disconnect();
      }
    });
  }
}

module.exports = WebSocketService;
